import axios from 'axios';
import { h } from 'vue';
import { IconFaceFrownFill } from '@arco-design/web-vue/dist/arco-vue-icon';
import { Message, Modal } from '@arco-design/web-vue';
import tool from '@/utils/tool';
import { get, isEmpty } from 'lodash';
import qs from 'qs';
import router from '@/router';
import { useAdminStore } from '@/store';

function createExternalService() {
  // 创建一个外部网络 axios 实例
  const service = axios.create();

  // HTTP request 拦截器
  service.interceptors.request.use(
    config => config,
    error => Promise.reject(error),
  );

  // HTTP response 拦截器
  service.interceptors.response.use(
    response => response,
    error => {
      Promise.reject(error.response ?? null);
    }
  );
  return service;
}

function createService () {
  // 创建一个 axios 实例
  const service = axios.create();

  // HTTP request 拦截器
  service.interceptors.request.use(
    config => config,
    error => {
      // 失败
      console.log(error);
      return Promise.reject(error);
    }
  );

  // HTTP response 拦截器
  service.interceptors.response.use(
    response => {
      const res = response.data;
      if ((response.headers['content-disposition'] || !/^application\/json/.test(response.headers['content-type'])) && response.status === 200) {
        return response;
      } else if (res.code !== 200 || res.status === 0) {
        if (res.code === 401) {
          throttle(() => {
            Modal.error({
              title: '确认退出',
              content: '登录已过期，请重新登录',
              okText: '重新登录',
              async onOk() {
                const adminStore = useAdminStore();
                await adminStore.logout();
                router.push({name: 'login'});
              },
            });
          })();
        } else {
          Message.error({
            content: res.msg || 'Error',
            duration: 5 * 1000,
            icon: () => h(IconFaceFrownFill),
          });
          // 状态码错误，阻止提交
          return Promise.reject(res.msg || 'Error');
        }
      }
      return res;
    },
    error => {
      // const res = error.response.data;
      const err = (text) => {
        Message.error({
          content: (error.response && error.response.data && error.response.data.msg)
          ? error.response.data.msg
          : text,
          icon: () => h(IconFaceFrownFill),
        });
      }
      if (error.response && error.response.data) {
        const errMsg = error.response.data.msg || error.response.data.message;
        switch (error.response.status) {
          case 404:
            err('服务器资源不存在');
            break;
          case 500:
            err(errMsg || '服务器内部错误');
            break;
          case 401:
            throttle(() => {
              // err('登录状态已过期，需要重新登录');
              // tool.local.clear();
              // router.push({name: 'login'});
              Modal.error({
                title: '确认退出',
                content: '登录已过期，请重新登录',
                okText: '重新登录',
                async onOk() {
                  const adminStore = useAdminStore();
                  await adminStore.logout();
                  router.push({name: 'login'});
                },
              });
            })();
            break;
          case 403:
            err('没有权限访问该资源');
            break;
          default:
            err('未知错误！');
        }
      } else {
        err('请求超时，服务器无响应！');
      }
      return Promise.reject(error.response && error.response.data ? error.response.data : null);
    }
  );
  return service;
}

// 节流
function throttle(fn, wait = 1500) {
  return function () {
    let context = this;
    if (!throttle.timer) {
      fn.apply(context, arguments);
      throttle.timer = setTimeout(function () {
        throttle.timer = null;
      }, wait);
    }
  };
}

function stringify (data) {
  return qs.stringify(data, { allowDots: true, encode: false });
}

/**
 * @description 创建请求方法
 * @param service
 * @param externalService
 */
function createRequest (service, externalService) {
  return function (config) {
    const env = import.meta.env;
    const { protocol } = document.location;
    const baseUrl = env.VITE_APP_OPEN_PROXY === 'true' ? env.VITE_APP_PROXY_PREFIX : `${protocol}${env.VITE_API_BASE_URL}`;
    const token = tool.local.get(env.VITE_APP_TOKEN_PREFIX);
    const setting = tool.local.get('setting');
    const configDefault = {
      headers: Object.assign(
        {
          Authorization: 'Bearer ' + token,
          'Accept-Language': setting?.language || 'zh_CN',
          'Content-Type': get(config, 'headers.Content-Type', 'application/json;charset=UTF-8'),
          token: token,
          sourceUi: 'arco-design',
        },
        config.headers,
      ),

      timeout: 10000,
      // baseURL: baseUrl,
      data: {},
    }
    delete config.headers;
    const option = Object.assign(configDefault, config);

    // json
    if (!isEmpty(option.params)) {
      option.url = option.url + '?' + stringify(option.params);
      option.params = {};
    }

    if (!/^(http|https)/g.test(option.url)) {
      option.baseURL = baseUrl;
      return service(option);
    } else {
      return externalService(option);
    }
  }
}

export const service = createService();
export const externalService = createExternalService();
export const request = createRequest(service, externalService);
